﻿using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Daemon;
using JetBrains.ReSharper.Daemon.Stages;
using JetBrains.ReSharper.Daemon.Stages.Dispatcher;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.CSharp;
using JetBrains.ReSharper.Psi.CSharp.Tree;
using JetBrains.ReSharper.Psi.Tree;
using JetBrains.ReSharper.Psi.Util;
using SPCAFContrib.ReSharper.Common;
using SPCAFContrib.ReSharper.Common.Attributes;
using SPCAFContrib.ReSharper.Common.CodeAnalysis;
using SPCAFContrib.ReSharper.Common.Extensions;
using SPCAFContrib.ReSharper.Consts;
using SPCAFContrib.ReSharper.Inspection.Code.SPCAF;

[assembly: RegisterConfigurableSeverity(SPC040213Highlighting.CheckId,
  null,
  Consts.SPCAF_DESIGN_GROUP,
  SPC040213Highlighting.CheckId + ": " + SPC040213Highlighting.Message,
  "WebParts should be inherited from the ASP.NET Webpart.",
  Severity.WARNING,
  false, Internal = false)]

namespace SPCAFContrib.ReSharper.Inspection.Code.SPCAF
{
    [ElementProblemAnalyzer(new[] { typeof(IClassLikeDeclaration) },
        HighlightingTypes = new[] {typeof (SPC040213Highlighting)})]
    [Applicability(
        IDEProjectType.SP2010FarmSolution |
        IDEProjectType.SPSandbox |
        IDEProjectType.SP2013FarmSolution |
        IDEProjectType.SPServerAPIReferenced)]
    public class DoNotInheritWebPartsFromSharePoint : ElementProblemAnalyzer<IClassLikeDeclaration>
    {
        protected override void Run(IClassLikeDeclaration element, ElementProblemAnalyzerData analyzerData,
            IHighlightingConsumer consumer)
        {
            IPsiSourceFile sourceFile = element.GetSourceFile();

            if (sourceFile != null)
            {
                if (sourceFile.HasExcluded(analyzerData.SettingsStore)) return;

                IProject project = sourceFile.GetProject();

                if (project != null)
                {
                    if (project.IsApplicableFor(this))
                    {
                        if (IsInvalid(element))
                        {
                            consumer.AddHighlighting(
                                new SPC040213Highlighting(element),
                                element.GetDocumentRange(),
                                element.GetContainingFile());
                        }
                    }
                }
            }
        }

        public static bool IsInvalid(IClassLikeDeclaration element)
        {
            bool result = false;
            
            ITypeElement declaredClassTypeElement = element.DeclaredElement;

            if (declaredClassTypeElement is IClass)
            {
                IDeclaredTypeUsage parentClassDeclarationUsage = element.SuperTypeUsageNodes.FirstOrDefault();
                if (parentClassDeclarationUsage != null)
                {
                    IDeclaredType parentClassDeclaredType = CSharpTypeFactory.CreateDeclaredType(parentClassDeclarationUsage);
                    if (parentClassDeclaredType.GetClrName().Equals(ClrTypeKeys.SPWebPart))
                    {
                        result = true;
                    }
                    else
                    {
                        IDeclaredElement parentClassDeclaredElement = null;
                        var declaredTypeUsage2 = parentClassDeclarationUsage as IUserDeclaredTypeUsage;
                        if (declaredTypeUsage2 != null)
                        {
                            IReferenceName typeName = declaredTypeUsage2.TypeName;
                            if (typeName != null)
                                parentClassDeclaredElement = typeName.Reference.Resolve().DeclaredElement;
                        }
                        else
                            parentClassDeclaredElement = parentClassDeclaredType.GetTypeElement();

                        if (parentClassDeclaredElement != null)
                        {
                            if (parentClassDeclaredElement is IClass)
                            {
                                IEnumerable<IDeclaredType> parentTypes =
                                    (parentClassDeclaredElement as IClass).GetAllSuperClasses();
                                result =
                                    parentTypes.Any(parentType => parentType.GetClrName().Equals(ClrTypeKeys.SPWebPart));
                            }
                        }
                    }
                }
            }

            return result;
        }
        
    }
    
    [ConfigurableSeverityHighlighting(CheckId, CSharpLanguage.Name, OverlapResolve = OverlapResolveKind.NONE, ShowToolTipInStatusBar = true)]
    public class SPC040213Highlighting : IHighlighting
    {
        public const string CheckId = "SPC040213";
        public const string Message = "Do not inherit WebParts from Microsoft.SharePoint.WebPartPages.WebPart";

        public IClassLikeDeclaration Element { get; private set; }

        public SPC040213Highlighting(IClassLikeDeclaration element)
        {
            this.Element = element;
        }

        #region IHighlighting Members

        public string ToolTip
        {
            get
            {
                return String.Format("{0}: {1}", CheckId, Message);
            }
        }
        public string ErrorStripeToolTip
        {
            get { return ToolTip; }
        }

        public int NavigationOffsetPatch
        {
            get { return 0; }
        }

        public bool IsValid()
        {
            return this.Element != null && this.Element.IsValid();
        }

        #endregion
    }
}
